/**
 * \file guiclass.h
 *
 * \brief Enthält die Klasse gui.
 */

#include <cairo.h>
#include <gtkmm.h>
#include <sstream>
#include <string>
#include <iostream>
 #include <gtk/gtkgl.h>
#include <gdk/gdkglglext.h>
#include "regelwerk.h"
#include "zustand.h"
#include "dateimanager.h"
#include "aktionsmanager.h"
//using namespace Gtk;
//class viewer;

/**
@class gui

@brief erstellt gui und verwaltet inputs

*/
class gui
    {   //varis
    int copydimx;/**< Alte Breite des Fensters, um unnoetiges Neuzeichnen zu verhindern*/
    int copydimy;/**< Alte Hoehe des Fensters, um unnoetiges Neuzeichnen zu verhindern*/
        Feld *fe;
        Regelwerk *re;
        Viewer* anzeiger;
        Aktionsmanager *ac;
        Dateimanager *da;
        Zustand *zu;
        Gtk::FileChooserDialog *dialog, *savdialog;
        Gtk::Entry * entry;
        GtkWidget *     drawing_area_old, *window;
        Gtk::ScrolledWindow *sex;
        Gtk::DrawingArea *drawing_area;
        Gtk::Fixed*fixed1,*fixed2,*fixed_newmapwindow;
        Gtk::VBox *box;
        Gtk::HScrollbar *hscrollbarx;
        Gtk::VScrollbar *hscrollbary;
        Gtk::Window *cwindow,*dwindow;
        Gtk::Window *ruleswindow, *newmapwindow;
        Gtk::Adjustment *adjx,*adjy;
        Gtk::Adjustment *adjzoom,*adjspeed,*spin_button_adjustment,*spin_x_adj,*spin_y_adj,*adjstepps,*adjskipp;
        Gtk::SpinButton *spin_button, *spin_x,*spin_y,*spin_stepps,*spin_skipp;
        Gtk::HScale *HSc_zoom,*HSc_speed;
        Gtk::VBox *vbox1, *vbox2;
        Gtk::HBox *vboxsavemen;
        Gtk::HBox *hbox;
        Gtk::Button   *button,*button2,*buttonstepp,*mkey,*reset,*newmapkey;
        Gtk::ToggleButton *tbutton;
        Gtk::MenuBar   *m_MenuBar;
        Gtk::Menu *m_Menu_File, *m_Menu_Edit;
        Gtk::Table *table;
        Gtk::Label *generation,*zoomtext,*speedtext,*skiptext,*steptext;
        Gtk::Label *geburt,*dod,*ziffer[9],*label_hoehe,*label_breite,*label_savemenu;
        Gtk::CheckButton *m_CheckButton_b[9], *m_cb_random;
        Gtk::CheckButton *m_CheckButton_t[9];
        //bool leb[9],stirb[9];
        double scxalt;/**< Wert der Scrollbar fuer X-Achse, um unnoetiges Neuzeichnen zu verhindern */
        double scyalt;/**< Wert der Scrollbar fuer Y-Achse, um unnoetiges Neuzeichnen zu verhindern */
        //int screenmaxx,screenmaxy; // maximale aufloesung vom bildschirm
       GdkGLConfig *glconfig;   /**< Konfig fuer OpenGl */
     // Da wir eine Multi Threaded Anwendung schreiben muessen wird eine
    // Moeglichkeit finden wie wir problemlos auf Daten/Funktionen/Methoden
    // in einem anderen Thread zugreifen kann. Dies kann man dann via
    // einem Glib::Dispatcher realisieren.
       
       Glib::Dispatcher m_dispatcher; /**< Dispatcher (d.h Funktion) mit denen man das Zeichnen des Feldes von einen anderen Thread aufrufen kann. Fuer weitere Informationen zu Dispatcher besuchen sie: http://developer.gnome.org/glibmm/unstable/classGlib_1_1Dispatcher.html */
       Glib::Dispatcher savedialogdis; /**< Dispatcher, mit denen man das Erscheinen der Speichern-ist-Fertig Meldung von einen anderen Thread aufrufen kann */
       Glib::Dispatcher zoom_dispatcher; /**< Dispatcher, mit denen man den Optimalen Zoom von einen anderen Thread aufrufen kann */
       
       Glib::Mutex *drawingmutex;  /**< mutex dafuer, dass Aktionsmanager erst das alte zu malende Feld ueberschreiben darf, wenn es Angezeigt wurde */
          Glib::Thread *   m_thread;
          Glib::RefPtr<Gtk::UIManager> m_refUIManager;
          Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup,action_group ;
          int drawn; /**< verhindert das Expose Event, welches sofort nach dem Erstellen des Fensters auftritt, indem diese Variable bis zum Anzeigen des ersten leeren Feldes auf 0 gesetzt wird */
        
/**
* @brief Erstellt Nachricht, dass Speichern erfolgreich ist.
*
* Man kann von einem anderen Thread keine Message Dialoge erstellen (Geometry error von GTK)
* deshalb wurde diese Funktion erstellt, um sie von dem anderen Thread per Dispatcher aufzurufen.
*/
       
       void savemessage();
       
/**
* @brief laesst beim Aufrufen des Konstruktors eine Leeres 1x1 Feld erstellen
*
* Laesst beim Aufrufen des Konstruktors eine Leeres 1x1 Feld erstellen.
* ansonsten ist bei einigen Versionen von GDK bzw Betriebsystemen, das Feld, welches
* unsere Generationen anzeigt, mit dem Bild des Hintergrunds gefuellt.
*/
        void programmstart();
        
/**
* @brief Wird vom anderen Thread mittels Dispatcher aufgerufen, um die Generation neu zu zeichnen. 
*/
        void on_activity_step();
        
/**
* @brief Killt Fenster.
* @param ev zeiger auf beliegiges GTK-Event, was geloescht werden soll.
*/
        bool killall(GdkEventAny* ev); 
     
/**
* @brief Blendet Gitter und rotes Rechteck aus, wenn wir mit Maus das Darstellungs-Fenster verlassen.
* @param event generiert, wenn der Mauszeiger das Fenster verlaesst
*
* Blendet Gitter und rotes Rechteck aus, wenn wir mit Maus das Darstellungs-Fenster verlassen,
* leider nicht zuverlaessig, wenn wir zu schnell mit der Maus unterwegs sind. 
*/
        gboolean mausverlassen(GdkEventCrossing* event);
        
/**
* @brief Zeichnet Generation neu, wenn die Drawing-Area neu gezeichnet werden muss.
* @param e wird generiert, wenn ein das Fenster oder ein Teil davon neu gezeichnet werden muss
*
* Theoretisch sollte das event aufgerufen werden, wenn die Drawing-Area verdeckt gewesen ist 
* und neugezeichnet werden soll, passiert aber nur, wenn Fenster aus Screen gezogen wird.
*/
        bool on_expose_event(GdkEventExpose* e);
        
/**
* @brief Zeichnet Generation neu, wenn das Fenster veraendert wird (groesse / Position).
* @param event wird generiert, wenn die Position oder Groesse eines Fensters sich geaendert hat
*/
        void on_my_configure_event(GdkEventConfigure* event);
/**
* @brief Leitet den Mausklick auf das Generations-Fenster im REC-MODUS an den Viewer weiter.
* @param event wird von Gtk vorrausgesetzt, enthaelt Daten ueber die Eingabe, wie zb welcher Button gedrueckt wurde
*/
        bool mausklick(GdkEventButton *event);
        
/**
* @brief Veranlasst Viewer das rote Rechteck an Position der Maus zu zeichen, wenn Gui im REC-MODUS ist.
* @param event wird von Gtk vorausgesetzt, enthaelt Daten wie zb Position der Maus etc
*/
        bool mausmalen(GdkEventMotion *event);
        
/**
* @brief Zeichnet Generation neu, wenn Scrollbalken verschoben wurden.
*/
        void scrollbar_cb();

/**
* @brief Speichert im Zustandsmanager die Geschwindigkeit, wenn man diese aendert.
*/
        void speedchange();
 
/**
* @brief Zeichnet Generation neu, wenn Zoom veraendert wurde.
*/ 
        void zoomchange();
      
/**
* @brief Berechnet Zoom beim Neuerstellen so, dass Feld noch ins Fenster passt, und uebergibt ihn an der Zustandsmanager.
*/ 



        void optzoom(); // berechnet optimalen zoom aus
        
/**
* @brief Fuehrt Aktionen aus, wenn man in Datei-> NEU auf Button Create klickt.
*/ 
        void newmap_mkey_clicked(); 
        
/**
* @brief Ruft das Menue zum Erstellen eines neuen Feldes auf.
*/ 
        void neu_golmapmenu(); 
       
/**
* @brief Beendet Gui, wenn Menue-punkt Ende aufgerufen.
*/ 
        void on_menu_end() ; 
     
/**
* @brief Ruft Datei-Speicher-Menue auf.
*/ 
        void on_menu_save() ;  

/**
* @brief Holt den Beschreibungs-Text der GOL-Dateien, wenn Nutzer sich im Datei-Laden-Menue befindet.
*/ 
        void on_my_file_activated();  
        
/**
* @brief Ruft Datei-Laden-Menue auf.
*/ 
        void on_menu_load();
        
/**
* @brief Resetet die Regeln im Regel-Menue.
*/ 
        void rules_reset_clicked();
      
/**
* @brief Speichert die Regeln im Regel-Menue.
*/ 
        void rules_mkey_clicked();
        
/**
* @brief Ruft das Regel-Menue auf.
*/ 
        void on_menu_rules();
        
        
/**
* @brief Startet die Berechnung in Endlos-Schleife.
*/ 
        void button_clicked(); // play botton gedrueckt

/**
* @brief Stoppt die Berechnung.
*/ 
        void button2_clicked(); // stop button gedrueckt
        
/**
* @brief Startet/Beendet den REC-Modus.
*/ 
        void button3_clicked(); // rec button gedrueckt
        
/**
* @brief Fuehrt bestimmte Anzahl an Schritten aus.
*/ 
        void buttonstepp_clicked(); // single step botton gedrueckt
        
/**
* @brief Erstellt saemtliche Fenster und deren Inhalte.
*
* Erstellt alle Fenster wie das Generations-Fenster, das Kontroll-Fenster
* und die anderen Menues, inklusive Buttons, etc.
*/ 
        void drawgui();
       
        public:
         
/**
* @brief Konstruktor der gui
* @param argc Programmname, benoetigt fuer GTK-Schleife
* @param argv[i] i-ter Aufrufparameter, benoetigt fuer Gtk-Schleife
*
*
* Erstellt die Main Windows, zeigt diese an, erstellt saemtliche Objekte (feld, regelwerk, aktionsmanager, dateimanager, viewer)
* und startet die Gtk-Schleife, die die Benutzereingaben einfängt etc.
* 
*
*/   
            
        gui(int argc, char *argv[]);
       
       
       
        };

